package com.hockeo.shared.domain;

import com.google.gwt.user.client.rpc.IsSerializable;

/**
 * Base class for all domain classes.
 *
 * @param <S> type of the actual first non abstract subclass
 * @param <T> type of the entity's ID (for persistent classes either String or Long)
 * @version $Id$
 * @author jjanke
 */
public abstract class AbstractDomain<S extends AbstractDomain<S, T>, T> implements IsSerializable
{
  /**
   * Returns the entity's ID.
   */
  public abstract T getId();

  /**
   * Returns the persistent entity's unique name. Usually this corresponds to the entity
   * class' simple name.
   */
  public abstract String getEntityName();

  @SuppressWarnings( "unchecked" )
  @Override
  public boolean equals( Object obj )
  {
    try
    {
      return getId().equals( ( (S) obj ).getId() );
    }
    catch ( Exception ex )
    {
      // ClassCastException may occur if the passed object is not of type S
      //
      return false;
    }
  }

  @Override
  public int hashCode()
  {
    return getId().hashCode();
  }

  /**
   * Returns the entity name followed by its id and possibly other properties provided by
   * the {@link #propertiesForToString()} method which should be overridden if
   * necessary.
   */
  @Override
  public String toString()
  {
    StringBuilder sb = new StringBuilder( " [ id: " ).append( getId() ).append( " " );
    Object[][] aobjProps = propertiesForToString();

    if ( aobjProps != null )
      for ( int i = 0; i < aobjProps.length; i++ )
        sb.append( ", " ).append( aobjProps[i][0] ).append( ": " ).append( aobjProps[i][1] );

    return getEntityName() + sb.append( " ]" ).toString();
  }

  /**
   * Returns a two-dimensional array, where each entry corresponds to one property and its
   * current value which should be included in the output of the {@link #toString()}
   * method.
   *
   * @return array where each element (identified by the first index) is enlisted by its
   *         name (index 0 of 2nd dimension) and its current value (index 1 of 2nd
   *         dimension) or <code>null</code> to not add anything but the entity's id to
   *         the output of toString().
   */
  protected Object[][] propertiesForToString()
  {
    return null;
  }
}
